#include "SinglePointCrossover.h"

template <typename T>
    SinglePointCrossover<T>::SinglePointCrossover()
{
//    cout << "Throwing exception" << endl;
    throw Unsupported_template_exception();
}

SinglePointCrossover<PermutationEncodedSolution>::SinglePointCrossover()
{
 //   cout << "PES Solution created" << endl;
}

SinglePointCrossover<BitEncodedSolution>::SinglePointCrossover()
{
  //  cout << "BES Solution created" << endl;
}

SinglePointCrossover<ValueEncodedSolution<int> >::SinglePointCrossover()
{
   // cout << "VES Solution created" << endl;
}

SinglePointCrossover<ValueEncodedSolution2d<bool> >::SinglePointCrossover()
{
}

/*
 * A singlePointCrossver for a permutation encoded solution involves choosing the crossover point,
 * copying everything up until that crossover point from one parent, and then populat the rest
 * of the permutation with the missing numbers in the order that the second parent has them.
 */
void SinglePointCrossover<PermutationEncodedSolution>::cross(Solution *parent1, Solution *parent2, Solution* &child1, Solution* &child2)
{
    PermutationEncodedSolution* pesParent1 = (PermutationEncodedSolution*) parent1;
    PermutationEncodedSolution* pesParent2 = (PermutationEncodedSolution*) parent2;
    PermutationEncodedSolution* pesChild1 = new PermutationEncodedSolution();
    PermutationEncodedSolution* pesChild2 = new PermutationEncodedSolution();
    
    vector<int> parent1Solution = pesParent1->getSolution();
    vector<int> parent2Solution = pesParent2->getSolution();

    //if we don't meet the prerequisites for doing a singlepoint crossover, then abort
    if ((parent1Solution.size() != parent2Solution.size()) || (parent1Solution.size() == 0))
    	throw Invalid_solution_size_exception();
        
    int crossoverPoint = MyRandom::randInt(0, parent1Solution.size() - 1);
    
    for (int i = 0; i < crossoverPoint; ++i)
    {
        pesChild1->addElement(parent1Solution[i]);
        pesChild2->addElement(parent2Solution[i]);
    }
        
    for (unsigned int i = 0; i < parent2Solution.size(); ++i)
    {
    	try
    	{
	        pesChild1->addElement(parent2Solution[i]);
    	}
    	catch (Invalid_element_exception &e)
    	{
    		// Don't care
    	}
    	
    	try
    	{
     	   pesChild2->addElement(parent1Solution[i]);
    	}
    	catch (Invalid_element_exception &e)
    	{
    		// Don't care
    	}
    }   

    child1 = pesChild1;
    child2 = pesChild2;
}

void SinglePointCrossover<BitEncodedSolution>::cross(Solution *parent1, Solution *parent2, Solution* &child1, Solution* &child2)
{
    BitEncodedSolution* besParent1 = (BitEncodedSolution*) parent1;
    BitEncodedSolution* besParent2 = (BitEncodedSolution*) parent2;
    BitEncodedSolution* besChild1  = (BitEncodedSolution*) besParent1->clone();
    BitEncodedSolution* besChild2  = (BitEncodedSolution*) besParent2->clone();
    
    unsigned int minLength = min(besParent1->getSize(), besParent2->getSize());
    unsigned int crosspoint = MyRandom::randInt(0, minLength);
    
    for (unsigned int x = 0; x < crosspoint; x++) 
    {
        besChild1->setBit(x, besParent2->getBit(x));
        besChild2->setBit(x, besParent1->getBit(x));
    }
    
    child1 = besChild1;
    child2 = besChild2;
}

void SinglePointCrossover<ValueEncodedSolution<int> >::cross(Solution *parent1, Solution *parent2, Solution* &child1, Solution* &child2)
{
    ValueEncodedSolution<int>* vesParent1 = (ValueEncodedSolution<int>*) parent1;
    ValueEncodedSolution<int>* vesParent2 = (ValueEncodedSolution<int>*) parent2;
    ValueEncodedSolution<int>* vesChild1  = (ValueEncodedSolution<int>*) vesParent1->clone();
    ValueEncodedSolution<int>* vesChild2  = (ValueEncodedSolution<int>*) vesParent2->clone();
    
    if (vesParent1->getSize() != vesParent2->getSize())
        throw Invalid_solution_size_exception();
    
    int crossoverPoint = MyRandom::randInt(0, vesParent1->getSize() - 1);
    
    for (int i = 0; i < crossoverPoint; ++i)
    {
        vesChild1->setElement(i, vesParent2->getElement(i));
        vesChild2->setElement(i, vesParent1->getElement(i));
    }
    
    child1 = vesChild1;
    child2 = vesChild2;
}

void SinglePointCrossover<ValueEncodedSolution2d<bool> >::cross(Solution *parent1, Solution *parent2, Solution* &child1, Solution* &child2)
{
    ValueEncodedSolution2d<bool>* ves2dParent1 = (ValueEncodedSolution2d<bool>*) parent1;
    ValueEncodedSolution2d<bool>* ves2dParent2 = (ValueEncodedSolution2d<bool>*) parent2;
    ValueEncodedSolution2d<bool>* ves2dChild1 = (ValueEncodedSolution2d<bool>*) ves2dParent1->clone();
    ValueEncodedSolution2d<bool>* ves2dChild2 = (ValueEncodedSolution2d<bool>*) ves2dParent2->clone();
    
    if (ves2dParent1->getRowCount() != ves2dParent2->getRowCount())
        throw Invalid_solution_size_exception();
    
    int rowCrossoverPoint = MyRandom::randInt(0, ves2dParent1->getRowCount() - 1);
    
    for (int i = 0; i < rowCrossoverPoint; ++i)
    {
	    if (ves2dParent1->getColumnCount(i) != ves2dParent2->getColumnCount(i))
	        throw Invalid_solution_size_exception();
            
        for (unsigned int j = 0; j < ves2dParent1->getColumnCount(i); ++j)
        {
            ves2dChild2->setValue(i, j, ves2dChild1->getValue(i, j));
        }
    }
    
    for (unsigned int i = rowCrossoverPoint; i < ves2dChild1->getRowCount(); ++i)
    {
        for (unsigned int j = 0; j < ves2dParent1->getColumnCount(i); ++j)
        {
            ves2dChild2->setValue(i, j, ves2dChild1->getValue(i, j));
        }
    }
    
    child1 = ves2dChild1;
    child2 = ves2dChild2;
}

template class SinglePointCrossover<BitEncodedSolution>;
template class SinglePointCrossover<PermutationEncodedSolution>;
template class SinglePointCrossover<ValueEncodedSolution<int> >;
template class SinglePointCrossover<ValueEncodedSolution2d<bool> >;
